#include "connection.h"
#include "handle.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "tools/config.h"
#include "tools/tools.h"

http_connection::http_connection(int id)
    : m_id(-1), m_req_type(HTTP_REQ_UNDEF), m_req_body_len(0), m_req_body(NULL)
{
    m_id = id;
}

http_connection::~http_connection()
{
    if (m_req_body)
    {
        delete[] m_req_body;
        m_req_body = NULL;
    }
    //printf("销毁连接:%d %d %x\n", getpid(), m_id, this);
}

bool http_connection::analyse_http_protocol(int fd)
{
    bool ret = false;
    //接收http协议头
    ret = recv_http_head(fd);
    if (!ret)
    {
        return false;
    }

    //分析http协议头
    analyse_head();
    //分析请求包体长度
    analyse_req_body_len();
    //接收http包体
    recv_http_body(fd);

    http_handle handle(m_req_type, m_req_url,
                       m_map_head, m_map_param,
                       m_req_body, m_req_body_len);
    ret = handle.init();
    if (!ret)
    {
        //handle 初始化失败
        return false;
    }

    ret = handle.process();
    if (!ret)
    {
        //process 处理失败
        return false;
    }

    //获取处理结果

    m_respones_data = handle.get_respones().data();

    return true;
}

bool http_connection::recv_http_head(int fd)
{
    char sz[10240] = {0x0};
    int len = 0; //总接收长度
    int ret_len = -1;
    int old_len_end = 0; //上一次行尾的位置

    m_vec_http_head.clear();

    while (true)
    {
        //按1个字节读取
        ret_len = read(fd, &sz[len], 1);
        //返回-1 可能是因为没有body
        if (ret_len == -1)
        {
            break;
        }

        if (ret_len == 0)
        {
            break;
        }

        if (ret_len == 1)
        {
            //当读到 \n 时则代表行结束
            if (sz[len] == '\n')
            {
                //如果读到空行的 \n 则表示头部分接收完毕
                if (sz[len - 1] == '\r' &&
                    sz[len - 2] == '\n' &&
                    sz[len - 3] == '\r')
                {
                    break; //读取完成，跳出接收循环
                }
                else
                {
                    int head_len = len - old_len_end + 2;
                    char *z = new char[head_len + 1]();
                    memcpy(z, sz + old_len_end, head_len);

                    m_vec_http_head.push_back(z);
                    delete[] z;
                    old_len_end = len + 1;
                }
            }

            //长度计数
            len = len + ret_len;
        }
    }
    return true;
}

//分析http头
void http_connection::analyse_head()
{
    for (size_t i = 0; i < m_vec_http_head.size(); i++)
    {
        std::string &str = m_vec_http_head[i];
        std::size_t pos = str.find(":");
        if (pos == std::string::npos)
        {
            //分析http 请求类型、请求地址及参数、请求协议版本
            std::size_t pos1 = str.find_first_of(" ");
            std::size_t pos2 = str.find_last_of(" ");

            std::string req_type = str.substr(0, pos1);
            std::string req_url = str.substr(pos1 + 1, pos2 - pos1);
            std::string req_version = str.substr(pos2 + 1, (str.length() - pos2) - 2);

            //分析请求类型
            analyse_req_type(req_type.c_str());

            //分析url和请求参数
            analyse_req_url(req_url);
        }
        else
        {
            std::string head_key = str.substr(0, pos);
            std::string head_value = str.substr(pos + 1, (str.length() - pos) - 2);
            //存储
            m_map_head[head_key] = head_value;
        }
    }
    return;
}

void http_connection::analyse_req_type(const char *req_type)
{
    if (0 == strcmp(req_type, "GET"))
    {
        m_req_type = HTTP_REQ_GET;
    }
    else if (0 == strcmp(req_type, "POST"))
    {
        m_req_type = HTTP_REQ_POST;
    }
    else if (0 == strcmp(req_type, "HEAD"))
    {
        m_req_type = HTTP_REQ_HEAD;
    }
    else if (0 == strcmp(req_type, "PUT"))
    {
        m_req_type = HTTP_REQ_PUT;
    }
    else if (0 == strcmp(req_type, "DELETE"))
    {
        m_req_type = HTTP_REQ_DELETE;
    }
    else if (0 == strcmp(req_type, "OPTIONS"))
    {
        m_req_type = HTTP_REQ_OPTIONS;
    }
    else if (0 == strcmp(req_type, "TRACE"))
    {
        m_req_type = HTTP_REQ_TRACE;
    }
    else if (0 == strcmp(req_type, "CONNECT"))
    {
        m_req_type = HTTP_REQ_CONNECT;
    }
    else if (0 == strcmp(req_type, "PATCH"))
    {
        m_req_type = HTTP_REQ_PATCH;
    }
    else if (0 == strcmp(req_type, "PROPFIND"))
    {
        m_req_type = HTTP_REQ_PROPFIND;
    }
    else if (0 == strcmp(req_type, "PROPPATCH"))
    {
        m_req_type = HTTP_REQ_PROPPATCH;
    }
    else if (0 == strcmp(req_type, "MKCOL"))
    {
        m_req_type = HTTP_REQ_MKCOL;
    }
    else if (0 == strcmp(req_type, "LOCK"))
    {
        m_req_type = HTTP_REQ_LOCK;
    }
    else if (0 == strcmp(req_type, "UNLOCK"))
    {
        m_req_type = HTTP_REQ_UNLOCK;
    }
    else if (0 == strcmp(req_type, "COPY"))
    {
        m_req_type = HTTP_REQ_COPY;
    }
    else if (0 == strcmp(req_type, "MOVE"))
    {
        m_req_type = HTTP_REQ_MOVE;
    }
    else if (0 == strcmp(req_type, "LINK"))
    {
        m_req_type = HTTP_REQ_LINK;
    }
    else
    {
        m_req_type = HTTP_REQ_UNDEF;
    }
}

void http_connection::analyse_req_url(std::string &url)
{
    std::size_t pos = url.find_first_of("?");
    if (std::string::npos == pos)
    {
        //不存在参数
        m_req_url = url.substr(0, (url.length() - 1));
    }
    else
    {
        m_req_url = url.substr(0, pos);
        std::string req_param = url.substr(pos + 1, (url.length() - pos));
        analyse_req_param(req_param);
    }
}

void http_connection::analyse_req_param(std::string &param)
{
    //参数分组
    std::vector<std::string> vec_param;
    {
        std::size_t last = 0;
        //使用&符号进行分割
        std::size_t pos = param.find_first_of("&", last);

        while (std::string::npos != pos)
        {
            vec_param.push_back(param.substr(last, pos - last));
            //+1 跳过分隔符
            last = pos + 1;
            pos = param.find_first_of("&", last);
        }

        if (pos - last > 0)
        {
            vec_param.push_back(param.substr(last, pos - last));
        }
    }

    //分解参数
    for (std::size_t i = 0; i < vec_param.size(); i++)
    {
        std::string &str = vec_param[i];
        std::size_t pos = str.find_first_of("=");
        if (pos != std::string::npos)
        {
            std::string param_key = str.substr(0, pos);
            std::string param_value = str.substr(pos + 1, (str.length() - pos));

            m_map_param[param_key] = param_value;
        }
    }
}

void http_connection::analyse_req_body_len()
{
    auto ite = m_map_head.find("Content-Length");
    if (ite != m_map_head.end())
    {
        m_req_body_len = atoi(ite->second.c_str());
    }
    else
    {
        m_req_body_len = 0;
    }
}

bool http_connection::recv_http_body(int fd)
{
    if (fd == 0)
    {
        return true;
    }
    m_req_body = new char[m_req_body_len];
    memset(m_req_body, 0, m_req_body_len);
    recv_n(fd, m_req_body, m_req_body_len);
    return true;
}

int http_connection::recv_n(int fd, char *buf, int len)
{
    int ret = 0;
    int n = len;
    char *ptr = buf;
    while (n > 0)
    {
        ret = read(fd, ptr, n);
        if (-1 == ret)
        {
            return -1;
        }

        if (0 == ret)
        {
            return ret;
        }

        n -= ret;
        ptr += ret;
    }
    return len;
}

const char *http_connection::get_respones()
{
    return m_respones_data;
}
